'''

Created on May 17, 2011



@author: Stelios Voutsinas

'''

from tempfile import NamedTemporaryFile

""" Web py DSC Masters project 2.0"""





import web

import sys

import urllib

import urllib2

import httplib

import VOTable

from  VOTable import VOTable

from  VOTable import VONode

import time

import StringIO

import cgi 

import html_functions

import xml_parser

import dateutil.parser as parser

import os

import re

import xml.dom.minidom

import xml.dom.minidom

import xml.dom





### Mail Information

web.config.smtp_server = 'smtp.gmail.com'

web.config.smtp_port = 587

web.config.smtp_username = 'username@gmail.com'

web.config.smtp_password = 'pass'

web.config.smtp_starttls = True





### Configurations

mode_global = 'async'

request = 'doQuery'

format = 'votable'

lang = 'ADQL'

DR2TAPurl = 'http://wfaudata.roe.ac.uk/ukidssWorld-dsa//TAP/'





### Url mappings

urls = ('/', 'index','/save_as_vot','save_as_vot','/save_as_html','save_as_html','/viewer','viewer','/send_email','send_email')

render = web.template.render('templates/')

app = web.application(urls, globals())



def generate_form_data(registry):

    #fetch array of results from registry

    query = """

    declare namespace ri='http://www.ivoa.net/xml/RegistryInterface/v1.0';

    for $x in //ri:Resource

    where $x/capability[@standardID='ivo://ivoa.net/std/TAP']

    and $x/@status='active'

    return $x/capability[@standardID='ivo://ivoa.net/std/TAP']/interface/accessURL

    """

    result_xml=""

    results=[]

    form_data=[]

    try:

        params = urllib.urlencode({'performquery' : 'true', 'ResourceXQuery' : query}) 

        req = urllib2.Request(registry, params)

        f = urllib2.urlopen(req)

        dom = xml.dom.minidom.parseString(f.read())

        dom_results=dom.getElementsByTagName("accessURL")

        for i in dom_results:

            form_data.append(web.form.Checkbox(xml_parser.getText(i)))

        f.close()

    except IOError:

        print "A network connection error occurred"

    return tuple(form_data)



my_form = web.form.Form(web.form.Textarea('textfield',web.form.notnull,row=200,cols=30, class_='textfield', id='textfield',description=''),web.form.Hidden(name='tap_endpoint',id='tap_endpoint'))

tap_endpoint_form = web.form.Form(*generate_form_data('http://registry.astrogrid.org/astrogrid-registry/main/xqueryresults.jsp'))



### globals

t_globals = {'datestr': web.datestr }

ERROR_HTML = "<div style=\"color:red;margin-left:50px;\">No elements returned. Please check your query</div>"

delay = 3





################## Main Methods ########################



def generate_endpoint_from_list(list):

    print list

    return DR2TAPurl 



def fetch_metadata(tap_endpoint):

    return_str = ''

    try:

        #Execute job and start loop requests for results

        #http://wfaudata.roe.ac.uk/ukidssWorld-dsa//VOSI/tables

        f = urllib.urlopen(tap_endpoint)

        dom_str = f.read()

        dom = xml.dom.minidom.parseString(dom_str) 

        return_str = xml_parser.handleXML(dom)

    except IOError:

       print "A network connection error occurred"        

    return return_str

    



# Print a votable as an HTML table for the table viewer (include ID for each entry)

def print_tables_for_viewer(votable,tbl_id,tbl_class):    

    result = ''

    if votable!='':

        fields = votable.getFields()

        result = '<table id="' +tbl_id + '" class="' +tbl_class + '" border="0" cellpadding="0" cellspacing="1"><thead><tr>'

        # votable tablesorter

        if isinstance(fields,VONode):

             attr = fields.getAttributes ()

             try: description = fields.DESCRIPTION.content

             except: description = ''

             name = attr.get ('name')

             ucd = attr.get ('ucd')

             result +="<th>"+ name +"</th>"  # %s,%s,%s % (name, ucd, description)  

        else:

            for i,fd in enumerate (fields):

                attr = fd.getAttributes ()

                try: description = fd.DESCRIPTION.content

                except: description = ''

                name = attr.get ('name')

                ucd = attr.get ('ucd')

                result +="<th>"+ name +"</th>"  # %s,%s,%s % (name, ucd, description)            

        result += "</tr></thead><tbody>"

        rows = votable.getDataRows ()

        getData = votable.getData

        for row in rows:

           result += "<tr>" 

           for i in getData(row):

               result += "<td>" + '<a href="static/photos/image1.jpg" title="Some description">' + i +"</a>" + "</td>"

           result += "</tr>"   

        result += "</tbody></table>"   

    else:

        result = "No results returned.."        

    return result    







# Change the destruction time for a TAP job

def change_destruction_time(url,new_time):

# text='Thu, 16 Dec 2010 12:14:05 +0000'

# date=(parser.parse(text))

# print(date.isoformat())

# 2010-12-16T12:14:05+00:00



    try:

        params = urllib.urlencode({'DESTRUCTION' : new_time}) 

        url = url+'/destruction'

        req = urllib2.Request(url, params)

        f = urllib2.urlopen(req)

        f.close()

    except IOError:

        print "A network connection error occurred"





# Open the given url and URI and read/return the result 

def get_async_results(url, URI):

    res = ''

    try:

        req = urllib2.Request(url+URI)

        f = urllib2.urlopen(req)

        res =  f.read()

        f.close()

    except IOError:

        print "A network connection error occurred"

    return res





# Takes a TAP url and starts a loop that checks the phase URI and returns the results when completed

def start_async_loop(url):

    return_vot = ''

    try:

        while True:

            res = get_async_results(url,'/phase')

            if res=='COMPLETED': 

                votable = VOTable ()

                return_vot = VOTable(url + '/results/result') 

                break

            elif res=='ERROR' or res== '':

                return return_vot

            else : 

                print res

            time.sleep(delay)

    except IOError:

        print "A network connection error occurred"

    return return_vot    

        



# Generate HTML content for HTML table save button

def printSaveHTMLTableInfo(html_tbl):

    result = """<div id="save_as"> 

                <form name="save_as_html" action="save_as_html" method="post">

                <input type="hidden" name="html_tbl" value =" """             

    result += html_functions.escape(html_tbl) + """ "/>

                <input type="submit" class ="save_button" value="Save as HTML" />

                </form>

                </div>

            """

    return result

    

    

# Generate HTML content for VOTable save button    

def printSaveVOTableInfo(vot):    

    #f = NamedTemporaryFile(dir='static/tmp',delete=False)

    output = StringIO.StringIO()

    vot.printAllNodes(func=output.write)

    

    result = """<div id="save_as"> 

                <form name="save_as_vot" action="save_as_vot" method="post">

                <input type="hidden" name="votbl" value =" """ 

    result += html_functions.escape(output.getvalue()) + """ "/>

                <input type="submit" class ="save_button" value="Save as VOTable" />

                </form>

                </div>

            """

    output.close()

    return result





                

# Execute an Asynchronous ADQL query on a TAP service

def execute_async_query(url,mode_local,q):

    """ Execute a query (q) against a TAP service (url + mode:sync|async) """

    params = urllib.urlencode({'REQUEST': request, 'LANG': lang, 'FORMAT': format, 'QUERY' : q}) 

    full_url = url+mode_local

    votable = ''

    result = ''

    html_table = ''

    jobId= 'None'

    #httplib.HTTPConnection.debuglevel = 1 

    try:

        #Submit job and get job id 

        req = urllib2.Request(full_url, params)

        opener = urllib2.build_opener()

        f = opener.open(req)

        jobId = f.url



        #Execute job and start loop requests for results

        req2 = urllib2.Request(jobId+'/phase',urllib.urlencode({'PHASE' : 'RUN'}))

        opener2 = urllib2.build_opener()

        f2 = opener.open(req2)

    

        # Return results as a votable object

        votable = start_async_loop(jobId)

    except IOError:

       print "A network connection error occurred"        

    return (votable,jobId)

    

    

# Generates HTML content for results from a query    

def generate_HTML_from_query((votable,jobId),query,tap_endpoint):    

        # Generate HTML for results section

    if votable!='' and votable.root.getNodeList()[0].getNodeList()[0].getNodeList()[0].getAttributes()['value'] != 'ERROR''':            

        html_table=printTables(votable,'votable','tablesorter')

        result = printSaveVOTableInfo(votable)

        result += printSaveHTMLTableInfo(html_table)

        result += '<div style="text-align:left;margin-left:50px;font-size:13px;">Query URL :  '+'<a href="'+jobId+'">'+ jobId + '</a>' + '</div><br>'

        result += '<form class="left" action="viewer" method="post" target="_new"><input type="hidden" name="query" value="'+ query +'"/><input type="hidden" name="tap_endpoint" value="'+ tap_endpoint +'"/><input type="hidden" name="results" value="' + html_functions.escape(printTables(votable,'votable','tablesorter'))  +'" /><input type="submit" value="Launch in Viewer"/></form>'

        result += '<div id=\"table_results\">' + html_table + '</div>'

    else : 

        result = "<div style=\"color:red;margin-left:50px;\">Please enter a correct query</div>"    

    return result    

    



# Print a votable as an HTML table

def printTables(votable,tbl_id,tbl_class):    

    result = ''

    try:

        if votable!='':

            fields = votable.getFields()

            result = '<table id="' +tbl_id + '" class="' +tbl_class + '" border="0" cellpadding="0" cellspacing="1"><thead><tr>'

            if isinstance(fields,VONode):

                 attr = fields.getAttributes ()

                 try: description = fields.DESCRIPTION.content

                 except: description = ''

                 name = attr.get ('name')

                 ucd = attr.get ('ucd')

                 result +="<th>"+ name +"</th>"  # %s,%s,%s % (name, ucd, description) 

            else: 

                for i,fd in enumerate (fields):

                    attr = fd.getAttributes ()

                    try: description = fd.DESCRIPTION.content

                    except: description = ''

                    name = attr.get ('name')

                    ucd = attr.get ('ucd')

                    result +="<th>"+ name +"</th>"  # %s,%s,%s % (name, ucd, description)            

            result += "</tr></thead><tbody>"

            rows = votable.getDataRows ()

            getData = votable.getData

            for row in rows:

               result += "<tr>" 

               for i in getData(row):

                   result += "<td>" + i + "</td>"

               result += "</tr>"   

            result += "</tbody></table>"   

        else:

            result = "No results returned.."

    except IOError:

        print "Unexpected error:", sys.exc_info()[0]

    return result    









################## Main webpy class ####################



class index:

    def GET(self):

        web.header("Content-Type", "text/html")

        form = my_form()

        tap_endpoints = tap_endpoint_form()

        return render.index(form, "",tap_endpoints)

           

    def POST(self):

        data = web.input(tap_endpoints="none",display="no",generated_tap="none")

        form = my_form()       

        tap_endpoints = tap_endpoint_form()

        results_html_val = "No elements returned. Please check your query"

        metadata = ""

        tap_endpoint=""

        

        if data.tap_endpoints!="none":

            tap_endpoint=generate_endpoint_from_list(data.tap_endpoints.strip())

            return tap_endpoint

        elif data.generated_tap!="none":

            tap_endpoint = data.generated_tap

        else:

            return "Please select from the list of TAP endpoints"

    

        if data.display == 'yes':

            if tap_endpoint!="":

                print "Fetching metadata from: " + tap_endpoint

                metadata = fetch_metadata(tap_endpoint[0:tap_endpoint.find('TAP')] + "VOSI/tables")

            else:

                return "No TAP endpoints selected"

            return metadata

        

        # Check for validation

        if tap_endpoint=="":

            return "Please select from the list of TAP endpoints before submitting a query"

        elif form.validates():

            # Get query from textfield and execute it / Get mode based on radio buttons

            query = form['textfield'].value.strip()

            results_html_val = generate_HTML_from_query(execute_async_query(tap_endpoint,mode_global,query),query,tap_endpoint)

            return results_html_val    

        else:

            return ERROR_HTML







################## Save as VOTable URL ####################



class save_as_vot:

    def GET(self):

        raise web.seeother('/')



    def POST (self):

        web.header('Content-Type', 'application/x-votable+xml')

        data = web.input(votbl="no data")

        return data.votbl    







################## Save as HTML URL ####################



class save_as_html:

    def GET(self):

        raise web.seeother('/')



    def POST (self):

        web.header('Content-Type', 'multipart/form-data')

        data = web.input(html_tbl="no data")

        return data.html_tbl    







################## Viewer HTML URL ####################



class viewer:

    def GET(self):

        raise web.seeother('/')

    

    def POST (self):

        data = web.input(results="",query="",xaxis="",yaxis="",tap_endpoint="")

        result = ''

        viewer_table=''

        if data.xaxis != "" and data.yaxis!="":

            new_query = 'SELECT ' + data.xaxis + ',' + data.yaxis + ' FROM ('+ data.query + ') AS query'

            votable,id = execute_async_query(data.tap_endpoint,mode_global,new_query)

            if votable!='' and votable.root.getNodeList()[0].getNodeList()[0].getNodeList()[0].getAttributes()['value'] != 'ERROR''':            

                viewer_table='<span style="font-size:13px;font-style:italic;padding-bottom:52px;">The following table displays the results of your plot query</span>'

                viewer_table+=printTables(votable,'viewer_table','tablesorter')

            else : 

                viewer_table = "<div style=\"color:red;margin-left:50px;\">Please enter correct column expressions</div>"    

        table = html_functions.unescape(data.results)

        result = '<div id=\"table_results\">' + table + '</div>'

        if viewer_table=='':

            return render.viewer(result,'value="'+ data.query + '"','value="'+ data.tap_endpoint + '"')   

        else :

            return viewer_table





################## Send Email URL ####################



class send_email:

    def GET(self):

        raise web.seeother('/')



    def POST (self):

        data = web.input(email="",query="",tap_endpoint="")

        (votable,jobId) = execute_async_query(data.tap_endpoint,mode_global,data.query)

        

        if votable!='' and votable.root.getNodeList()[0].getNodeList()[0].getNodeList()[0].getAttributes()['value'] != 'ERROR''':            

            html_table=printTables(votable,'','')

            result = '<div style="text-align:left;margin-left:40px;">Query URL :  '+'<a href="'+jobId+'">'+ jobId + '</a>' + '</div><br>'

            result += '<div>' + html_table + '</div>'

        else : 

            result = "<div style=\"color:red;margin-left:50px;\">Your ADQL request was not executed. Please check your query</div>"    

        web.utils.sendmail('gadva1g@gmail.com', data.email, 'TAP Results', result,headers=({ 'Content-Type': 'text/html; charset=utf-8'}))

        return ""   

                

# main

def is_test():

    if 'WEBPY_ENV' in os.environ:

        print "Initializing test"

        return os.environ['WEBPY_ENV'] == 'test'



if (not is_test()) and __name__ == "__main__": app.run()




